/**
 * Created by Forcs on 15/7/2.
 */
(function($){

  var Wancake = function() {

  };

  //
  Wancake.asyncTask = function() {
    var asyncTask = new AsyncTask();
    asyncTask.then.apply(asyncTask, arguments);
    return asyncTask;
  };

  AsyncTask = function() {
    var self = this;

    self.State = {
      PENDING : 1
      , IDLE : 2
    };

    self._subscriber = [];
    self._doneCallback = null;
    self._current = null;
    self._state = self.State.IDLE;

  };

  AsyncTask.prototype._enqueue = function() {
    var self = this;
    var args = arguments;
    var length = args.length;
    var s = {};
    if (length > 0 && typeof args[0] === 'function') {
      s.task = args[0];
    }
    if (length > 1 && typeof args[1] === 'function') {
      s.done = args[1];
    }
    if (length > 2 && typeof args[2] === 'function') {
      s.fail = args[2];
    }

    if (self._state == self.State.PENDING) {
      self._subscriber.push(s);
    } else {
      self._current = s;
      self._execTask(s);
    }

  };

  AsyncTask.prototype._execTask = function(subscriber) {
    var self = this;
    if (subscriber && subscriber.task !== undefined
        && typeof subscriber.task === 'function') {
      self._state = self.State.PENDING;
      subscriber.task.apply(self, [self]);
    }
  };

  AsyncTask.prototype._next = function() {
    var self = this;
    if (self._subscriber && self._subscriber.length) {
      var curr = self._current = self._subscriber.shift();
      if (curr && curr.task !== undefined
          && typeof curr.task == 'function') {
        self._execTask(curr);
      }
    } else {
      if (self._doneCallback) {
        self._doneCallback.apply(self, []);
      }
    }
  };

  AsyncTask.prototype._complete = function(fn, args) {
    var self = this;
    fn.apply(self, args);
  };

  AsyncTask.prototype.then = function() {
    var self = this;
    self._enqueue.apply(self, arguments)
    return self;
  };

  AsyncTask.prototype.resolve = function() {
    var self = this;
    var curr = self._current;
    if (curr && curr.done !== undefined
        && typeof curr.done === 'function') {
      self._complete(curr.done, arguments);
    }
    self._state = self.State.IDLE;
    self._next();
  };

  AsyncTask.prototype.reject = function() {
    var self = this;
    var curr = self._current;
    if (curr && curr.fail !== undefined
        && typeof curr.fail === 'function') {
      self._complete(curr.fail, arguments);
    }
    self._state = self.State.IDLE;
    self._next();
  };

  AsyncTask.prototype.done = function() {
    var self = this;
    var args = arguments;
    if (args && args.length && (typeof args[0] === 'function')) {
      self._doneCallback = args[0];
    }
  }


  Wancake.ajaxLooper = function() {
    var args = arguments;
    var ajaxLooper = null;
    if (args.length > 1) {
      ajaxLooper = new AjaxLooper(args[0], args[1])
    } else if (args.length > 0) {
      ajaxLooper = new AjaxLooper(args[0]);
    } else {
      throw new Error("至少有一个url参数");
    }
    return ajaxLooper;
  }

  AjaxLooper = function() {
    var self = this;

    self._successCallback = null;
    self._errorCallback = null;
    self._againCallback = null;
    self._doneCallback = null;

    self._url = null;
    self._option = null;

    self._intervalId = 0;

    var init = function() {
      var args = arguments;
      if (args && args.length > 0) {
        var arg = args[0];
        if (typeof arg === 'string') {
          self._url = arg;
        } else if (typeof  arg === 'object') {
          if (arg.url !== undefined && (typeof arg.url === 'string')) {
            self._url = arg.url;
            delete arg.url;
          }
          self._option = arg;
        }
      }
      if (args && args.length > 1) {
        if (typeof args[1] === 'object') {
          self._option = args[1];
        }
      }
    };

    init.apply(self, arguments);
  };

  AjaxLooper.prototype.start = function() {
    var self = this;
    self._run.apply(self);
  };

  AjaxLooper.prototype._run = function() {
    var self = this;
    $.ajax(self._url, self._option)
        .done(function(data) {
          if (self._successCallback) {
            self._successCallback.apply(self, [self, data]);
          }
        })
        .fail(function() {
          if (self._errorCallback) {
            self._errorCallback.apply(self, [self]);
          }
        });

    return self;
  };

  AjaxLooper.prototype._updateOption = function(opt) {
    var self = this;
    if (!self._option) {
      self._option = opt;
    } else {
      for (var attr in opt) {
        self._option[attr] = opt[attr];
      }
    }
  };

  AjaxLooper.prototype.onSuccess = function() {
    var self = this;
    if (arguments.length > 0 && (typeof arguments[0] === 'function')) {
      self._successCallback = arguments[0];
    }

    return self;
  };

  AjaxLooper.prototype.onError = function() {
    var self = this;
    if (arguments.length > 0 && (typeof arguments[0] === 'function')) {
      self._errorCallback = arguments[0]
    }

    return self;
  };

  AjaxLooper.prototype.again = function() {
    var self = this;
    if (self._againCallback) {
      var args = [];
      args.push(self);
      if (arguments && arguments.length) {
        var len = arguments.length;
        for (var i = 0; i < len; i++) {
          args.push(arguments[i]);
        }
      }
      var opt = self._againCallback.apply(self, args);
      self._updateOption(opt);
    }

    setTimeout(function() {
        self._run();
      }, 0);
  };

  AjaxLooper.prototype.onAgain = function() {
    var self = this;
    if (arguments.length > 0 && (typeof arguments[0] === 'function')) {
      self._againCallback = arguments[0];
    }

    return self;
  };

  AjaxLooper.prototype.done = function() {
    var self = this;
    if (self._doneCallback) {
      self._doneCallback.apply(self, arguments);
    }
  };

  AjaxLooper.prototype.onDone = function() {
    var self = this;
    if (arguments.length > 0 && (typeof arguments[0] === 'function')) {
      self._doneCallback = arguments[0];
    }

    return self;
  }

  AjaxLooper.prototype.getOption = function() {
    return this._option;
  };

  AjaxLooper.prototype.getUrl = function() {
    return this._url;
  };

  window.$w = window.wancake = Wancake;
})(jQuery);